package ee.az.test.lighting;

/**
 * @author Artur Zinatullin (artur.zinatullin@gmail.com) 2010
 */
public class VisibilityMapImpl extends AbstractMap<VisibilitySpot> implements VisibilityMap {

	private final int x;
	private final int y;
	protected final TransparencyMap transparencyMap;

	public VisibilityMapImpl(int x, int y, TransparencyMap transparencyMap) {
		super(transparencyMap.getWidth(), transparencyMap.getHeight());
		this.x = x;
		this.y = y;
		this.transparencyMap = transparencyMap;
		initVisibilityMap();
	}

	public boolean isVisible(int x, int y) {
		return getValue(x, y).isVisible();
	}

	@Override
	protected VisibilitySpot createDefaultSpot() {
		return new VisibleSpot();
	}
	
	protected void initVisibilityMap() {
		for (int i=0; i<getWidth(); i++) {
			initLine(getLine(x, y, i, 0));
		}
		for (int i=0; i<getWidth(); i++) {
			initLine(getLine(x, y, i, getHeight()-1));
		}
		for (int i=0; i<getHeight(); i++) {
			initLine(getLine(x, y, 0, i));
		}
		for (int i=0; i<getHeight(); i++) {
			initLine(getLine(x, y, getWidth()-1, i));
		}
	}
	
	public void initLine(Line line) {
		boolean visible = true;
		for (int i=0; i < line.getLength(); i++) {
			int x = line.getPoints()[i].getX();
			int y = line.getPoints()[i].getY();
			VisibilitySpot value = getValue(x, y);
			if ((value instanceof VisitedSpot)) {
				visible &= value.isVisible();
			} else {
				boolean transparent = transparencyMap.isTransparent(x, y);
				setValue(x, y, visible ? new VisibleSpot() : new InvisibleSpot());
				visible &= transparent;
			}
		}
	}

	private abstract class VisitedSpot implements VisibilitySpot {
		@Override
		public String toString() {
			return isVisible() ? "." : " ";
		}
	}
	
	public class VisibleSpot implements VisibilitySpot {
		public boolean isVisible() {
			return true;
		}
	}
	public class InvisibleSpot implements VisibilitySpot {
		public boolean isVisible() {
			return false;
		}
	}
	
	public int getViewPointX() {
		return x;
	}
	public int getViewPointY() {
		return y;
	}
}

